#include <QDebug>
#include <QStringBuilder>
#include <QStringList>
#include "RestoreCodeVisiter.h"
#include "ast/VisitorBase.h"
#include "ast/Suite.h"
#include "ast/commentType.h"

RestoreCodeVisiter::RestoreCodeVisiter()
{
    _tupleParens = 0;
    operatorMap[1] = "+";
    operatorMap[2] = "-";
    operatorMap[3] = "*";
    operatorMap[4] = "/";
    operatorMap[5] = "%";
    operatorMap[6] = "**";
    operatorMap[7] = "<<";
    operatorMap[8] = ">>";
    operatorMap[9] = "|";
    operatorMap[10] = "^";
    operatorMap[11] = "&";
    operatorMap[12] = "//";
}

QString RestoreCodeVisiter::code()
{
    return _code.join("");
}

void RestoreCodeVisiter::visitModule(const ModulePtr& node)
{
    beforeNode(node);
    qDebug() << "visit module";
    afterNode(node);
    node->traverse(this);
}

void RestoreCodeVisiter::visitInteractive(const InteractivePtr& node)
{
    qDebug() << "visit Interactive";
    node->traverse(this);
}

void RestoreCodeVisiter::visitExpression(const ExpressionPtr& node)
{
    qDebug() << "visit Expression";
    node->traverse(this);
}

void RestoreCodeVisiter::visitNameTok(const NameTokPtr& node)
{
    qDebug() << "visit NameTok";
    _code << node->id();
    node->traverse(this);
}

void RestoreCodeVisiter::visitSuite(const SuitePtr& node)
{
    qDebug() << "visit Suite";
    node->traverse(this);
}

void RestoreCodeVisiter::visitWithItem(const WithItemPtr& node)
{
    qDebug() << "visit WithItem";
    node->traverse(this);
}

void RestoreCodeVisiter::visitFunctionDef(const FunctionDefPtr& node)
{
    if(node->decs().length()){
        foreach(decoratorsTypePtr n, node->decs()){
            if(n != NULL){
                visitDecorator(n);
            }
        }
    }
    beforeNode(node);
    qDebug() << "visit FunctionDef";
    _code << "def ";
    node->name()->accept(this, node->name());
    _code << "(";
    if(node->args()){
    }
    _code << ")";
    if(node->returns()){
        _code << "->";
        node->returns()->accept(this, node->returns());
    }
    _code << ":";
    afterNode(node);
    //node->traverse(this);
}

void RestoreCodeVisiter::visitClassDef(const ClassDefPtr& node)
{
    qDebug() << "visit ClassDef";
    node->traverse(this);
}

void RestoreCodeVisiter::visitReturn(const ReturnPtr& node)
{
    qDebug() << "visit Return";
    node->traverse(this);
}

void RestoreCodeVisiter::visitDelete(const DeletePtr& node)
{
    _code << "del";
    if (node->target().length())
        _code << " ";
    qDebug() << "Visit delete";
    node->traverse(this);
}

void RestoreCodeVisiter::visitAssign(const AssignPtr& node)
{
    qDebug() << "visit Assign";
    node->traverse(this);
}

void RestoreCodeVisiter::visitAugAssign(const AugAssignPtr& node)
{
    qDebug() << "visit AugAssing";
    node->traverse(this);
}

void RestoreCodeVisiter::visitFor(const ForPtr& node)
{
    qDebug() << "visit For";
    node->traverse(this);
}

void RestoreCodeVisiter::visitWhile(const WhilePtr& node)
{
    qDebug() << "visit While";
    node->traverse(this);
}

void RestoreCodeVisiter::visitIf(const IfPtr& node)
{
    qDebug() << "visit If";
    node->traverse(this);
}

void RestoreCodeVisiter::visitWith(const WithPtr& node)
{
    qDebug() << "visit With";
    node->traverse(this);
}

void RestoreCodeVisiter::visitRaise(const RaisePtr& node)
{
    qDebug() << "visit Raise";
    node->traverse(this);
}

void RestoreCodeVisiter::visitTryExcept(const TryExceptPtr& node)
{
    qDebug() << "visit TryExcept";
    node->traverse(this);
}

void RestoreCodeVisiter::visitTryFinally(const TryFinallyPtr& node)
{
    qDebug() << "visit TryFinally";
    node->traverse(this);
}

void RestoreCodeVisiter::visitAssert(const AssertPtr& node)
{
    qDebug() << "visit Assert";
    node->traverse(this);
}

void RestoreCodeVisiter::visitImport(const ImportPtr& node)
{
    qDebug() << "visit Import";
    node->traverse(this);
}

void RestoreCodeVisiter::visitImportFrom(const ImportFromPtr& node)
{
    qDebug() << "visit ImportFrom";
    node->traverse(this);
}

void RestoreCodeVisiter::visitGlobal(const GlobalPtr& node)
{
    qDebug() << "visit Global";
    node->traverse(this);
}

void RestoreCodeVisiter::visitNonLocal(const NonLocalPtr& node)
{
    qDebug() << "visit NonLocal";
    node->traverse(this);
}

void RestoreCodeVisiter::visitExpr(const ExprPtr& node)
{
    qDebug() << "visit Expr";
    node->traverse(this);
}

void RestoreCodeVisiter::visitPass(const PassPtr& node)
{
    qDebug() << "visit Pass";
    node->traverse(this);
}

void RestoreCodeVisiter::visitBreak(const BreakPtr& node)
{
    qDebug() << "visit Break";
    node->traverse(this);
}

void RestoreCodeVisiter::visitContinue(const ContinuePtr& node)
{
    qDebug() << "visit Continue";
    node->traverse(this);
}

void RestoreCodeVisiter::visitBoolOp(const BoolOpPtr& node)
{
    qDebug() << "visit BoolOp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitBinOp(const BinOpPtr& node)
{
    qDebug() << "visit BinOp";
    node->left()->accept(this, node->left());
    _code << " " << operatorMap[node->op()] << " ";
    node->right()->accept(this, node->right());
}

void RestoreCodeVisiter::visitUnaryOp(const UnaryOpPtr& node)
{
    qDebug() << "visit UnaryOp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitLambda(const LambdaPtr& node)
{
    qDebug() << "visit Lambda";
    node->traverse(this);
}

void RestoreCodeVisiter::visitIfExp(const IfExpPtr& node)
{
    qDebug() << "visit IfExp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitDict(const DictPtr& node)
{
    qDebug() << "visit Dict";
    node->traverse(this);
}

void RestoreCodeVisiter::visitSet(const SetPtr& node)
{
    qDebug() << "visit Set";
    node->traverse(this);
}

void RestoreCodeVisiter::visitListComp(const ListCompPtr& node)
{
    qDebug() << "visit ListComp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitSetComp(const SetCompPtr& node)
{
    qDebug() << "visit SetComp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitDictComp(const DictCompPtr& node)
{
    qDebug() << "visit DictComp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitGeneratorExp(const GeneratorExpPtr& node)
{
    qDebug() << "visit GeneratorExp";
    node->traverse(this);
}

void RestoreCodeVisiter::visitYield(const YieldPtr& node)
{
    qDebug() << "visit Yield";
    node->traverse(this);
}

void RestoreCodeVisiter::visitCompare(const ComparePtr& node)
{
    qDebug() << "visit Compare";
    node->traverse(this);
}

void RestoreCodeVisiter::visitCall(const CallPtr& node)
{
    qDebug() << "visit Call";
    node->traverse(this);
}

void RestoreCodeVisiter::visitRepr(const ReprPtr& node)
{
    qDebug() << "visit Repr";
    node->traverse(this);
}

void RestoreCodeVisiter::visitNum(const NumPtr& node)
{
    qDebug() << "visit Num";
    _code << node->num();
    node->traverse(this);
}

void RestoreCodeVisiter::visitStr(const StrPtr& node)
{
    qDebug() << "visit Str";
    node->traverse(this);
}

void RestoreCodeVisiter::visitStrJoin(const StrJoinPtr& node)
{
    qDebug() << "visit StrJoin";
    node->traverse(this);
}

void RestoreCodeVisiter::visitAttribute(const AttributePtr& node)
{
    qDebug() << "visit Attribute";
    node->traverse(this);
}

void RestoreCodeVisiter::visitSubscript(const SubscriptPtr& node)
{
    qDebug() << "visit Subscript";
    node->traverse(this);
}

void RestoreCodeVisiter::visitStarred(const StarredPtr& node)
{
    qDebug() << "visit Starred";
    node->traverse(this);
}

void RestoreCodeVisiter::visitName(const NamePtr& node)
{
    _code << node->id();
    qDebug() << "visit Name";
    node->traverse(this);
}

void RestoreCodeVisiter::visitList(const ListPtr& node)
{
    qDebug() << "visit List";
    node->traverse(this);
}

void RestoreCodeVisiter::visitTuple(const TuplePtr& node)
{
    if (_tupleParens)
        _code << "(";
    qDebug() << "visit Tuple";
    node->traverse(this);
    if (node->elts().length() > 0){
        QStringList elts = _code.mid(_code.length() - node->elts().length());
        for(int i = 0; i < node->elts().length(); ++i)
            _code.removeLast();
        _code << elts.join(", ");
        _code << (node->endsWithComma()? ",":"");
    }
    if (_tupleParens)
        _code << ")";
}

void RestoreCodeVisiter::visitEllipsis(const EllipsisPtr& node)
{
    qDebug() << "visit Ellipsis";
    node->traverse(this);
}

void RestoreCodeVisiter::visitSlice(const SlicePtr& node)
{
    qDebug() << "visit Slice";
    node->traverse(this);
}

void RestoreCodeVisiter::visitExtSlice(const ExtSlicePtr& node)
{
    qDebug() << "visit ExtSlice";
    node->traverse(this);
}

void RestoreCodeVisiter::visitIndex(const IndexPtr& node)
{
    qDebug() << "visit Index";
    node->traverse(this);
}

void RestoreCodeVisiter::visitComprehension(const ComprehensionPtr& node)
{
    qDebug() << "visit Comprehension";
    node->traverse(this);
}

void RestoreCodeVisiter::beforeNode(const SimpleNodePtr& node)
{
    foreach(ObjectPtr c, node->specialsBefore){
        if(c.dynamicCast<commentType>()){
            commentTypePtr comment = c.dynamicCast<commentType>();
            _code << comment->id();
            //doc.add(comment.beginLine, comment.beginColumn, comment.id, comment);
        } else if(c.dynamicCast<Name>()) {
            NamePtr name = c.dynamicCast<Name>();
            _code << name->id();
            //doc.add(name.beginLine, name.beginColumn, name.id, name);
        } else if(c.dynamicCast<SpecialStr>()) {
            SpecialStrPtr specialStr = c.dynamicCast<SpecialStr>();
            //doc.add(specialStr.getBeginLine(), specialStr.getBeginCol(), specialStr.toString(), specialStr);
            _code << specialStr->toString();
        }
    }
}

void RestoreCodeVisiter::afterNode(const SimpleNodePtr& node)
{
    foreach(ObjectPtr c, node->specialsAfter){
        if(c.dynamicCast<commentType>()){
            commentTypePtr comment = c.dynamicCast<commentType>();
            _code << comment->id();
            //doc.add(comment.beginLine, comment.beginColumn, comment.id, comment);
        } else if(c.dynamicCast<Name>()) {
            NamePtr name = c.dynamicCast<Name>();
            _code << name->id();
            //doc.add(name.beginLine, name.beginColumn, name.id, name);
        } else if(c.dynamicCast<SpecialStr>()) {
            SpecialStrPtr specialStr = c.dynamicCast<SpecialStr>();
            //doc.add(specialStr.getBeginLine(), specialStr.getBeginCol(), specialStr.toString(), specialStr);
            _code << specialStr->toString();
        }
    }
}

void RestoreCodeVisiter::visitDecorator(const QSharedPointer<decoratorsType>& node)
{

}
